package com.module.my.model

import android.text.TextUtils
import cn.leancloud.LCObject
import cn.leancloud.LCQuery
import com.module.app.base.BaseViewModel
import com.module.app.bean.UserBean
import com.module.app.ext.modifyUserFlow
import com.module.app.network.getCommonService
import com.module.app.utils.UserUtils
import com.module.app.bean.IType
import com.module.base.ext.request
import com.module.base.ext.retry
import com.module.base.utils.CommonUtils
import com.module.base.utils.FileCommonUtils
import com.module.base.utils.LogUtils
import com.module.base.utils.ToastUtils
import com.module.frame.ext.postEvent
import com.module.my.R
import com.module.my.bean.LogOffUserBean
import com.module.third.learcloud.*
import com.module.third.qiniu.QiniuRerun
import com.module.third.qiniu.QiniuSignUtils
import com.module.third.qiniu.QiniuUtils
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.MutableSharedFlow
import kotlinx.coroutines.withContext
import retrofit2.HttpException
import java.io.File
import java.util.concurrent.CountDownLatch

class UserInfoViewModel : BaseViewModel() {

    /**
     *  退出登录
     */
    val logoutFlow: MutableSharedFlow<Boolean> by lazy(mode = LazyThreadSafetyMode.SYNCHRONIZED) {
        MutableSharedFlow()
    }

    /**
     *  注销
     */
    val logOffFlow: MutableSharedFlow<Boolean> by lazy(mode = LazyThreadSafetyMode.SYNCHRONIZED) {
        MutableSharedFlow()
    }

    /**
     *  验证验证码
     */
    val verifyCodeFlow: MutableSharedFlow<String> by lazy(mode = LazyThreadSafetyMode.SYNCHRONIZED) {
        MutableSharedFlow()
    }

    fun modifyName(name: String) {
        request({
            val userBean = com.module.app.utils.UserUtils.getUserBean()
            userBean.name = name
            lcSave(userBean, userBean.objectId, com.module.app.bean.UserBean::class.java)
        }, {
            check(it != null) {
                CommonUtils.getString(R.string.error_unknow)
            }
            setUserBean(it)
        }, {
            ToastUtils.showShort(it.msg)
        }, true)
    }

    fun modifySex(@com.module.app.bean.IType.ISex sex: Int) {
        request({
            val userBean = com.module.app.utils.UserUtils.getUserBean()
            userBean.sex = sex
            lcSave(userBean, userBean.objectId, com.module.app.bean.UserBean::class.java)
        }, {
            check(it != null) {
                CommonUtils.getString(R.string.error_unknow)
            }
            setUserBean(it)
        }, {
            ToastUtils.showShort(it.msg)
        }, true)
    }

    /**
     * 退出登录
     */
    fun logout() {
        request({
            val userBean = com.module.app.utils.UserUtils.getUserBean()
            userBean.deviceId = ""
            userBean.pushId = ""
            lcSave(userBean, userBean.objectId, com.module.app.bean.UserBean::class.java)
        }, {
            postEvent(logoutFlow, true)
        }, {
            ToastUtils.showShort(it.msg)
        }, true)
    }

    /**
     * 注销
     */
    fun logOff() {
        request({
            //删除用户信息
            var isDelSuc: LCResponse<Boolean> = lcDel(com.module.app.utils.UserUtils.getUserBean())
            //注销用户登记,由于以及删除用户信息了，需要登记成功，所以使用了失败重试
            if (isDelSuc.getData() == true) {
                retry(2000, 300) {
                    val logOffUserBean = LogOffUserBean()
                    logOffUserBean.inviter = com.module.app.utils.UserUtils.getInviter()
                    logOffUserBean.name = com.module.app.utils.UserUtils.getName()
                    if (!com.module.app.utils.UserUtils.getWx().isNullOrEmpty()) {
                        logOffUserBean.id = com.module.app.utils.UserUtils.getWx()
                    } else if (!com.module.app.utils.UserUtils.getQQ().isNullOrEmpty()) {
                        logOffUserBean.id = com.module.app.utils.UserUtils.getQQ()
                    } else if (!com.module.app.utils.UserUtils.getPhone().isNullOrEmpty()) {
                        logOffUserBean.id = com.module.app.utils.UserUtils.getPhone()
                    }
                    lcSave(logOffUserBean, LogOffUserBean::class.java)
                }
            }
            isDelSuc
        }, {
            postEvent(logOffFlow, it)
        }, {
            ToastUtils.showShort(it.msg)
        }, true)
    }

    fun binding(type: String, id: String, head: String?) {
        request({
            //查询账号
            var response: LCResponse<com.module.app.bean.UserBean> = queryAccount(type, id);
            //数据处理
            val userBean: com.module.app.bean.UserBean
            var objectId: String? = null
            if (response.getData() == null) {
                //数据为空 绑定账号
                userBean = com.module.app.utils.UserUtils.getUserBean()
                objectId = com.module.app.utils.UserUtils.getUserId()
                //如果头像为空，绑定头像
                if (TextUtils.isEmpty(userBean.headUrl)) {
                    userBean.headUrl = head
                }
                when (type) {
                    com.module.app.bean.IType.ILogin.QQ -> {
                        userBean.loginType = com.module.app.bean.IType.ILogin.QQ
                        userBean.qq = id
                    }
                    com.module.app.bean.IType.ILogin.WX -> {
                        userBean.loginType = com.module.app.bean.IType.ILogin.WX
                        userBean.wx = id
                    }
                    com.module.app.bean.IType.ILogin.PHONE -> {
                        userBean.loginType = com.module.app.bean.IType.ILogin.PHONE
                        userBean.phone = id
                    }
                }
            } else {
                //数据不为空，已经被绑定了，抛异常
                var msg = ""
                when (type) {
                    com.module.app.bean.IType.ILogin.QQ -> msg = "该QQ已经被绑定，请先解绑，才能再次绑定"
                    com.module.app.bean.IType.ILogin.WX -> msg = "该微信已经被绑定，请先解绑，才能再次绑定"
                    com.module.app.bean.IType.ILogin.PHONE -> msg = "该手机号已经被绑定，请先解绑，才能再次绑定"
                }
                throw IllegalStateException(msg)
            }
            lcSave(userBean, objectId, com.module.app.bean.UserBean::class.java)
        }, {
            check(it != null) {
                CommonUtils.getString(R.string.error_unknow)
            }
            setUserBean(it)
        }, {
            ToastUtils.showShort(it.msg)
        }, true)
    }

    /**
     *  取消绑定
     */
    fun unbinding(type: String) {
        request({
            var userBean = com.module.app.utils.UserUtils.getUserBean()
            when (type) {
                com.module.app.bean.IType.ILogin.QQ -> {
                    check(!(userBean.wx.isNullOrEmpty() && userBean.phone.isNullOrEmpty())) { "解绑失败，电话号码、微信、QQ至少绑定一个。" }
                    userBean.qq = ""
                }
                com.module.app.bean.IType.ILogin.WX -> {
                    check(!(userBean.qq.isNullOrEmpty() && userBean.phone.isNullOrEmpty())) { "解绑失败，电话号码、微信、QQ至少绑定一个。" }
                    userBean.wx = ""
                }
                com.module.app.bean.IType.ILogin.PHONE -> {
                    check(!(userBean.wx.isNullOrEmpty() && userBean.qq.isNullOrEmpty())) { "解绑失败，电话号码、微信、QQ至少绑定一个。" }
                    userBean.phone = ""
                }
            }
            lcSave(userBean, userBean.objectId, com.module.app.bean.UserBean::class.java)
        }, {
            check(it != null) {
                CommonUtils.getString(R.string.error_unknow)
            }
            setUserBean(it)
        }, {
            ToastUtils.showShort(it.msg)
        }, true)
    }

    fun sendCode(phone: String) {
        request({
            lcSendCode(phone, 10, CommonUtils.getString(R.string.app_name), "绑定")
        }, {
            if (it == true) {
                ToastUtils.showShort("短信发送成功,请注意查收")
            } else {
                throw IllegalStateException(CommonUtils.getString(R.string.error_unknow))
            }
        }, {
            ToastUtils.showShort(it.msg)
        }, true)
    }

    fun verifyCode(phone: String, code: String) {
        request({
            lcVerifyCode(phone, code)
        }, {
            if (it == true) {
                postEvent(verifyCodeFlow, phone)
            } else {
                throw IllegalStateException(CommonUtils.getString(R.string.error_unknow))
            }
        }, {
            ToastUtils.showShort(it.msg)
        }, true)
    }

    fun getUser() {
        request({
            val tClass = com.module.app.bean.UserBean::class.java
            val query = LCQuery<LCObject>(tClass.simpleName)
            query.whereEqualTo("objectId", com.module.app.utils.UserUtils.getUserId())
            lcQuerySingle(query, tClass)
        }, {
            check(it != null) {
                "没有找到该用户"
            }
            setUserBean(it)
        }, {
            ToastUtils.showShort(it.msg)
        }, true)
    }

    /**
     * 上传头像
     */
    fun modifyHead(headUrl: String) {
        request({
            LogUtils.e("开始上传头像")
            //图片不能超过
            check(FileCommonUtils.getFileSize(File(headUrl)) < 1024 * 1024) {
                CommonUtils.getString(R.string.my_upload_img_fail_too_big)
            }
            //七牛云上传头像
            var url = uploadHead(headUrl)
            //删除之前旧的头像，需要失败也要重试
            retry(2000, 200) {
                delHead(com.module.app.utils.UserUtils.getHeadUrl())
            }
            //更新服务器
            retry(2000, 200) {
                val userBean = com.module.app.utils.UserUtils.getUserBean()
                userBean.headUrl = url
                lcSave(userBean, userBean.objectId, com.module.app.bean.UserBean::class.java)
            }
        }, {
            check(it != null) {
                CommonUtils.getString(R.string.error_unknow)
            }
            postEvent(modifyUserFlow, true)
        }, {
            ToastUtils.showShort(it.msg)
        }, true)
    }

    /**
     * 七牛云上传头像
     */
    private suspend fun uploadHead(path: String): String {
        return withContext(Dispatchers.IO) {
            var url = ""
            val completeSingle = CountDownLatch(1)
            //1、上传七牛云
            QiniuUtils.upload(
                path,
                0,
                "head_" + com.module.app.utils.UserUtils.getUserId().toString() + "_" + System.currentTimeMillis(),
                object : QiniuUtils.Listener() {
                    override fun onSuc(qiniuRerun: QiniuRerun) {
                        super.onSuc(qiniuRerun)
                        url = qiniuRerun.getUrl()
                        completeSingle.countDown()
                    }

                    override fun onFail() {
                        super.onFail()
                        completeSingle.countDown()

                    }
                })
            completeSingle.await()
            if (url.isNullOrEmpty()) {
                throw java.lang.IllegalStateException("图片上传失败")
            }
            return@withContext url
        }
    }

    private suspend fun delHead(url: String): Boolean {
        var isSuc = false
        try {
            getCommonService().delQiniu(
                QiniuSignUtils.getDelEencodedEntryURI(QiniuUtils.getKey(url)),
                QiniuSignUtils.getManageToken(QiniuUtils.getKey(url))
            )
            isSuc = true
        } catch (e: Exception) {
            if (e is HttpException) {
                val exception = e as HttpException
                //指定资源不存在或已被删除。   目标资源已存在。
                if (exception.code() == 612 || exception.code() == 614) {
                    isSuc = true
                }
            }
        }
        check(isSuc) {
            "删除失败"
        }
        return isSuc
    }

    /**
     * 查询账号
     * 挂起函数
     */
    private suspend fun queryAccount(@com.module.app.bean.IType.ILogin type: String, id: String): LCResponse<com.module.app.bean.UserBean> {
        return withContext(Dispatchers.IO) {
            val tClass = com.module.app.bean.UserBean::class.java
            val query = LCQuery<LCObject>(tClass.simpleName)
            when (type) {
                com.module.app.bean.IType.ILogin.QQ -> query.whereEqualTo("qq", id)
                com.module.app.bean.IType.ILogin.WX -> query.whereEqualTo("config/wx", id)
                com.module.app.bean.IType.ILogin.PHONE -> query.whereEqualTo("phone", id)
            }
            return@withContext lcQuerySingle(query, tClass)
        }
    }

    private fun setUserBean(userBean: com.module.app.bean.UserBean) {
        com.module.app.utils.UserUtils.setUserBean(userBean)
        postEvent(modifyUserFlow, true)
    }
}